﻿using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace LINQToolKit.GData
{
    /// <summary>
    /// provides the linq queries for google data api
    /// </summary>
    /// <remarks>
    /// This framework is under the GNU licence and Creative Commons 3.0.
    /// You can also get a copy of the source code from google code
    /// <see cref="http://linqtodouban.googlecode.com/svn/trunk/"/>.
    /// For more information and further support, please contact with kevin (chwkai@gmail.com)
    /// </remarks>
    public static class GDataQueryExt
    {
        public static IQueryable<TSource> UpdatedBetween<TSource>(
            this IQueryable<TSource> source, DateTime start, DateTime end)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(start), Expression.Constant(end)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> UpdatedMin<TSource>(
            this IQueryable<TSource> source, DateTime time)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(time)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> UpdatedMax<TSource>(
            this IQueryable<TSource> source, DateTime time)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(time)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> PublishedBetween<TSource>(
            this IQueryable<TSource> source, DateTime start, DateTime end)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(start), Expression.Constant(end)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> PublishedMin<TSource>(
            this IQueryable<TSource> source, DateTime time)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(time)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> PublishedMax<TSource>(
            this IQueryable<TSource> source, DateTime time)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(time)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> Has<TSource>(this IQueryable<TSource> source, string keyword)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(keyword)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> NotHas<TSource>(this IQueryable<TSource> source, string keyword)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(keyword)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> InCategory<TSource>(this IQueryable<TSource> source, string category)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(category)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> AuthorBy<TSource>(this IQueryable<TSource> source, string author)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(author)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> AltAs<TSource>(this IQueryable<TSource> source, string alt)
        {
            var exprs = new Expression[] {
                source.Expression, Expression.Constant(alt)};
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(Expression.Call(null, method, exprs));
        }

        public static IQueryable<TSource> PrettyPrint<TSource>(this IQueryable<TSource> source)
        {
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(
                Expression.Call(null, method, source.Expression));
        }

        public static IQueryable<TSource> Strict<TSource>(this IQueryable<TSource> source)
        {
            var method = ((MethodInfo)MethodBase.GetCurrentMethod())
                .MakeGenericMethod(new Type[] { typeof(TSource) });

            return source.Provider.CreateQuery<TSource>(
                Expression.Call(null, method, source.Expression));
        }
    }
}
